﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI.WebControls;
using Medianamik.Core.DAL.Repositories;
using DALS = Medianamik.Core.DAL.SubSonicDAL;
using SubSonic;
using System.Data;
using System.Text.RegularExpressions;
using System.Threading;
using System.Collections;
using System.Collections.ObjectModel;
using Medianamik.Core.Sugar;
using System.Xml.Linq;
using System.Collections.Specialized;
using Medianamik.Core.Security;



namespace Medianamik.Core.DAL
{
    internal class SubsonicNodeTypeDALProvider : INodeTypeDALProvider
    {
        private readonly INodeTypeRepository _nodeTypeRepository;

        internal SubsonicNodeTypeDALProvider(INodeTypeRepository nodeTypeRepository)
        {
            _nodeTypeRepository = nodeTypeRepository;
        }
        
        public IEnumerable<HierarchicalRule> GetAllHierarchicalRules()
        {
            DALS.HierarchicalRuleCollection rules = new DALS.HierarchicalRuleCollection();
            rules.Where(DALS.HierarchicalRule.Columns.ParentItemType, false);
            rules.Load();

            return rules.Select(r => new HierarchicalRule() { ItemID = r.TypeId, ParentItemID = r.ParentItemId });
        }

        public IEnumerable<TypeTemplate> GetAllTemplates()
        {
            DALS.TypeTemplateCollection templates = new DALS.TypeTemplateCollection();
            templates.Load();

            return templates.Select(t => new TypeTemplate()
            {
                NodeTypeId = t.TypeId,
                TemplateId = t.TemplateId,
                WebSiteId = t.WebSiteId
            });
        }

        public bool PropertyHasDuplicateValues(Guid pPropertyID)
        {
            //TODO: Corriger 
            throw new NotImplementedException();
        }

        public List<NodeType> GetAllTypes(bool pIncludeManyToManys)
        {
            return _nodeTypeRepository.All(pIncludeManyToManys).ToList();
        }

        public IEnumerable<NodeTypeInterface> GetAllInterfaces()
        {
            var dalInterfaces = new DALS.InterfaceXCollection();
            dalInterfaces.OrderByAsc(DALS.InterfaceX.Columns.Name);
            dalInterfaces.Load();

            foreach (var dalInterface in dalInterfaces)
            {
                yield return FromDALInterface(dalInterface);
            }
        }

        public IEnumerable<NodeTypeInterfaceImplementation> GetNodeTypeInterfaces(Guid typeId)
        {
            var typeInterfaces = new DALS.TypeInterfaceCollection();
            typeInterfaces.Where(DALS.TypeInterface.Columns.TypeId, typeId);
            typeInterfaces.Load();

            foreach (var interf in typeInterfaces)
            {
                yield return FromDALTypeInterface(interf);
            }
        }

        public IEnumerable<NodeTypeInterfaceImplementation> GetNodeTypes(Guid interfaceId)
        {
            var typeInterfaces = new DALS.TypeInterfaceCollection();
            typeInterfaces.Where(DALS.TypeInterface.Columns.InterfaceId, interfaceId);
            typeInterfaces.Load();

            foreach (var interf in typeInterfaces)
            {
                yield return FromDALTypeInterface(interf);
            }
        }

        /// <summary>
        /// Vérifie l'existence d'un Type Medianamik avec le TypeName passé en paramètre.
        /// </summary>
        /// <param name="pTypeName">Le TypeName à vérifier</param>
        /// <param name="pTypeID" >Paramète de sortie. Le TypeID est retourné si le TypeName est trouvé</param>
        /// <returns>True si le Type existe, sinon False</returns>
        public bool NodeTypeExists(string pTypeName, out Guid pTypeID)
        {

            SubSonic.Query q = DALS.Type.Query();
            q.WHERE(DALS.Type.Columns.Name, pTypeName);
            q.Top = "1";
            q.SelectList = DALS.Type.Columns.TypeId;

            bool exists = false;
            pTypeID = Guid.Empty;
            using (IDataReader reader = q.ExecuteReader())
            {
                if (reader.Read())
                {
                    pTypeID = (Guid)reader[DALS.Type.Columns.TypeId];
                    exists = true;
                }
            }
            return exists;

        }

        public int TypeNodesCount(Guid pTypeID, bool blockInheritance)
        {
            if (blockInheritance)
            {
                Query q = DALS.Node.Query();
                q.WHERE(DALS.Node.Columns.TypeId, pTypeID.ToString());
                q.WHERE(DALS.Node.Columns.IsDeleted, false);

                return q.GetRecordCount();
            }
            return int.Parse(DALS.SPs.TypeNodesCount(pTypeID).ExecuteScalar().ToString());
        }
        
        public void TransacSave(IEnumerable<NodeTypeDataShell> nodeTypeDataShells)
        {
            var userName = Utility.GetCurrentUserName();
            var commands = new QueryCommandCollection();

            foreach (var nodeTypeDataShell in nodeTypeDataShells)
            {
                //NodeType
                if (nodeTypeDataShell.NodeType.Status == EntityStates.Deleted)
                {
                    //var command = DALS.SPs.DeleteNodeType(nodeTypeDataShell
                    //     .NodeType.ID).Command;

                    //command.CommandTimeout = 6000;

                    //commands.Add(command);

                    commands.AddRange(GetDeleteNodeTypeCommands(nodeTypeDataShell
                        .NodeType.ID));
                }
                else
                {
                    commands.Add(ToDALType(nodeTypeDataShell.NodeType)
                        .GetSaveCommand(userName));

                    //Properties
                    commands.AddRange(nodeTypeDataShell.Properties.Select(p => ToDALProperty(p)
                        .GetSaveCommand(userName)).NotNull());
                    commands.AddRange(nodeTypeDataShell.DeletedProperties.Select(p =>
                        new DeleteQuery(DALS.PropertyX.Schema)
                        .WHERE(DALS.PropertyX.Columns.PropertyId, p.ID).BuildDeleteCommand()).NotNull());

                    //HierarchicalTypeRules
                    commands.AddRange(nodeTypeDataShell.HierarchicalTypeRules.Select(r =>
                        ToDALHierarchicalRule(r.ParentItemID, r.ItemID).GetSaveCommand(userName))
                        .NotNull());
                    commands.AddRange(nodeTypeDataShell.DeletedHierarchicalTypeRules.Select(r =>
                        new DeleteQuery(DALS.HierarchicalRule.Schema)
                        .WHERE(DALS.HierarchicalRule.Columns.TypeId, r.ItemID)
                        .AddWhere(DALS.HierarchicalRule.Columns.ParentItemId, r.ParentItemID)
                        .AddWhere(DALS.HierarchicalRule.Columns.ParentItemType, false)
                        .BuildDeleteCommand()).NotNull());

                    //HierarchicalNodeRules
                    commands.AddRange(nodeTypeDataShell.HierarchicalNodeRules.Select(r =>
                        ToDALHierarchicalNodeRule(r.ParentItemID, r.ItemID).GetSaveCommand(userName))
                        .NotNull());
                    commands.AddRange(nodeTypeDataShell.DeletedHierarchicalNodeRules.Select(r =>
                        new DeleteQuery(DALS.HierarchicalRule.Schema)
                        .WHERE(DALS.HierarchicalRule.Columns.TypeId, r.ItemID)
                        .AddWhere(DALS.HierarchicalRule.Columns.ParentItemId, r.ParentItemID)
                        .AddWhere(DALS.HierarchicalRule.Columns.ParentItemType, true)
                        .BuildDeleteCommand()).NotNull());

                    //Templates
                    commands.AddRange(nodeTypeDataShell.Templates.Select(t => ToDALTypeTemplate(t)
                        .GetSaveCommand(userName)).NotNull());
                    commands.AddRange(nodeTypeDataShell.DeletedTemplates.Select(t =>
                        new DeleteQuery(DALS.TypeTemplate.Schema)
                        .WHERE(DALS.TypeTemplate.Columns.TypeId, t.NodeTypeId)
                        .AddWhere(DALS.TypeTemplate.Columns.TemplateId, t.TemplateId)
                        .AddWhere(DALS.TypeTemplate.Columns.WebSiteId, t.WebSiteId)
                        .BuildDeleteCommand()).NotNull());


                    //Interfaces
                    commands.AddRange(nodeTypeDataShell.Interfaces.Select(i => ToDALTypeInterface(i)
                        .GetSaveCommand(userName)).NotNull());
                    commands.AddRange(nodeTypeDataShell.DeletedInterfaces.Select(i =>
                        new DeleteQuery(DALS.TypeInterface.Schema)
                        .WHERE(DALS.TypeInterface.Columns.TypeId, nodeTypeDataShell.NodeType.ID)
                        .AddWhere(DALS.TypeInterface.Columns.Id, i.ID)
                        .BuildDeleteCommand()).NotNull());
                }
            }

            DataService.ExecuteTransaction(commands);
        }

        public void TransacSaveInterfaces(IEnumerable<NodeTypeInterfaceDataShell> nodeTypeInterfaceDataShells)
        {
            var userName = Utility.GetCurrentUserName();
            var commands = new QueryCommandCollection();

            foreach (var nodeTypeInterfaceDataShell in nodeTypeInterfaceDataShells)
            {
                if (nodeTypeInterfaceDataShell.NodeTypeInterface.Status == EntityStates.Deleted)
                {
                    commands.AddRange(GetDeleteNodeTypeInterfaceCommands(nodeTypeInterfaceDataShell
                        .NodeTypeInterface.ID));
                }
                else
                {

                    var saveCommand = ToDALInterface(nodeTypeInterfaceDataShell.NodeTypeInterface)
                        .GetSaveCommand(userName);
                    
                    if(saveCommand != null)
                        commands.Add(saveCommand);

                    //Properties
                    commands.AddRange(nodeTypeInterfaceDataShell.Properties.Select(p => ToDALInterfaceProperty(p)
                        .GetSaveCommand(userName)).NotNull());
                    commands.AddRange(nodeTypeInterfaceDataShell.DeletedProperties.Select(p =>
                        new DeleteQuery(DALS.InterfaceProperty.Schema)
                        .WHERE(DALS.InterfaceProperty.Columns.InterfacePropertyId, p.ID).BuildDeleteCommand()).NotNull());
                }
            }

            DataService.ExecuteTransaction(commands);
        }

        public QueryCommandCollection GetDeleteNodeTypeCommands(Guid pTypeID)
        {
            //Query pour supprimer les Properties
            //Cascade delete sur la table
            //Query queryProps = DALS.PropertyX.Query();
            //queryProps.QueryType = QueryType.Delete;
            //queryProps.WHERE(DALS.PropertyX.Columns.TypeId, pTypeID);

            //Query pour supprimer le Type
            var queryType = DALS.Type.Query();
            queryType.QueryType = QueryType.Delete;
            queryType.WHERE(DALS.Type.Columns.TypeId, pTypeID);

            //Query pour supprimer les noeuds
            var queryNode = DALS.Node.Query();
            queryNode.QueryType = QueryType.Delete;
            queryNode.WHERE(DALS.Node.Columns.TypeId, pTypeID);

            //Query pour supprimer les noeuds
            var queryRule = DALS.HierarchicalRule.Query();
            queryRule.QueryType = QueryType.Delete;
            queryRule.WHERE(DALS.HierarchicalRule.Columns.TypeId, pTypeID);
            queryRule.OR(DALS.HierarchicalRule.Columns.ParentItemId, pTypeID);

            var commands = new QueryCommandCollection();
            //commands.Add(queryProps.BuildCommand());
            commands.Add(queryRule.BuildCommand());
            commands.Add(queryNode.BuildCommand());
            commands.Add(queryType.BuildCommand());

            return commands;
        }

        public QueryCommandCollection GetDeleteNodeTypeInterfaceCommands(Guid interfaceId)
        {
            //Query pour supprimer les Properties
            //Cascade delete sur la table

            //Query pour supprimer l'interface
            var queryType = DALS.InterfaceX.Query();
            queryType.QueryType = QueryType.Delete;
            queryType.WHERE(DALS.InterfaceX.Columns.InterfaceId, interfaceId);

            var commands = new QueryCommandCollection();
            commands.Add(queryType.BuildCommand());

            return commands;
        }

        public IEnumerable<NodeTypeProperty> GetAllNodeTypeProperties()
        {
            return new DALS.PropertyXCollection().Load().Select(p => FromDALProperty(p));
        }

        public IEnumerable<NodeTypeInterfaceProperty> GetAllNodeTypeInterfaceProperties()
        {
            return new DALS.InterfacePropertyCollection().Load().Select(p => FromDALInterfaceProperty(p));
        }

        public void DeleteTypeProperty(Guid pTypePropertyID)
        {
            try
            {
                DALS.PropertyX.Delete(pTypePropertyID);
            }
            catch //(SqlException e)
            {
                throw;
            }
        }

        public void UpdateTypeProperty(NodeTypeProperty pTypeProperty)
        {
            ToDALProperty(pTypeProperty).Save();
        }

        public Collection<OneToManyRelation> GetPrimaryRelations(IEnumerable<Guid> pTypeIds)
        {
            object[] ids = pTypeIds.Select(g => g.ToString()).Cast<object>().ToArray();
            DALS.OneToManyRelationCollection col = new DALS.OneToManyRelationCollection();
            if (ids.Length > 0)
            {
                Query q = DALS.OneToManyRelation.Query();
                q.IN(DALS.OneToManyRelation.Columns.PrimaryTypeId, ids);

                using (IDataReader reader = q.ExecuteReader())
                {
                    col.Load(reader);
                }
            }

            Collection<OneToManyRelation> resultCol = new Collection<OneToManyRelation>(col.ToList().ConvertAll<OneToManyRelation>(r => FromDALOneToManyRelation(r)));

            return resultCol;
        }

        public Collection<OneToManyRelation> GetForeignRelations(IEnumerable<Guid> pTypeIds)
        {
            object[] ids = pTypeIds.Select(g => g.ToString()).Cast<object>().ToArray();
            DALS.OneToManyRelationCollection col = new DALS.OneToManyRelationCollection();
            if (ids.Length > 0)
            {
                Query q = DALS.OneToManyRelation.Query();
                q.IN(DALS.OneToManyRelation.Columns.ForeignTypeId, ids);
                using (IDataReader reader = q.ExecuteReader())
                {
                    col.Load(reader);
                }
            }

            Collection<OneToManyRelation> resultCol = new Collection<OneToManyRelation>(col.Select(r => FromDALOneToManyRelation(r)).ToList());

            return resultCol;
        }

        public Collection<ManyToManyRelation> GetManyToManyRelations(Guid pTypeId)
        {
            return GetManyToManyRelations(new Guid[] { pTypeId });
        }
        public Collection<ManyToManyRelation> GetManyToManyRelations(IEnumerable<Guid> pTypeIds)
        {
            object[] ids = pTypeIds.Select(g => g.ToString()).Cast<object>().ToArray();
            DALS.ManyToManyRelationCollection many2Manys = new DALS.ManyToManyRelationCollection();
            if (ids.Length > 0)
            {
                Query q = DALS.ManyToManyRelation.Query();
                q.IN(DALS.ManyToManyRelation.Columns.LeftPrimaryTypeId, ids);
                q.WHERE(DALS.ManyToManyRelation.Columns.ForeignTypeIsManyToMany, true);
                using (IDataReader reader = q.ExecuteReader())
                {
                    many2Manys.Load(reader);
                }
            }

            return new Collection<ManyToManyRelation>(many2Manys.Select(r => FromDALManyToManyRelation(r)).ToList());

        }
        
        #region Converters

        /// <summary>
        /// Converti un objet PropertyX du DAL SubSonic en NodeTypeProperty
        /// </summary>
        /// <param name="pDALProperty">L'objet PropertyX à convertir</param>
        /// <returns>Un objet de type NodeTypeProperty</returns>
        private static NodeTypeProperty FromDALProperty(DALS.PropertyX pDALProperty)
        {
            Unit? medCtrlWidth = null;
            if (!string.IsNullOrEmpty(pDALProperty.MedianamikControlWidth))
                medCtrlWidth = Unit.Parse(pDALProperty.MedianamikControlWidth);
            var medianamikControlSettings = new MedianamikControlInfo(medCtrlWidth
                     , pDALProperty.MedianamikControlHeight
                     , pDALProperty.TreeRootNodeId);
            Unit? priMedCtrlWidth = null;
            if (!string.IsNullOrEmpty(pDALProperty.PrimaryMedianamikControlWidth))
                priMedCtrlWidth = Unit.Parse(pDALProperty.PrimaryMedianamikControlWidth);
            var primaryMedianamikControlSettings = new MedianamikControlInfo(priMedCtrlWidth
                     , pDALProperty.PrimaryMedianamikControlHeight
                     , pDALProperty.PrimaryTreeRootNodeId);


            Regex validationRegex = string.IsNullOrEmpty(pDALProperty.ValidationRegex)
                      ? null
                      : new Regex(pDALProperty.ValidationRegex);

            NodeTypeProperty result = new NodeTypeProperty(pDALProperty.PropertyId,
                pDALProperty.Name,
                pDALProperty.MaxLength,
                pDALProperty.MinLength,
                pDALProperty.TypeId,
                pDALProperty.HaveTooltip,
                pDALProperty.IsLanguageNeutral,
                pDALProperty.IsRequired,
                pDALProperty.IsUnique,
                validationRegex,
                pDALProperty.GroupName,
                pDALProperty.MedianamikControlId,
                medianamikControlSettings,
                pDALProperty.DataTypeId,
                pDALProperty.PrimaryTypeId,
                pDALProperty.PrimaryPropertyId,
                pDALProperty.PrimaryMedianamikControlId,
                primaryMedianamikControlSettings,
                pDALProperty.PrimaryDataTypeId)
                {
                    Roles = RoleCollection.FromString(pDALProperty.Roles),
                    Flags = new BitVector32(pDALProperty.Flags),
                    Description = pDALProperty.Description,
                    IsGenerated = pDALProperty.IsGenerated,
                    IsDeleted = pDALProperty.IsDeleted
                };

            result.IsNew = false;
            result.Relationship = (NodeTypePropertyRelationship) pDALProperty.RelationshipId;

            return result;
        }

        private static NodeTypeInterfaceProperty FromDALInterfaceProperty(DALS.InterfaceProperty dalInterfaceProperty)
        {
            return new NodeTypeInterfaceProperty(dalInterfaceProperty.InterfacePropertyId,
                                                       dalInterfaceProperty.Name,
                                                       dalInterfaceProperty.Description,
                                                       dalInterfaceProperty.InterfaceId,
                                                       dalInterfaceProperty.DataTypeId,
                                                       dalInterfaceProperty.MaxLength,
                                                       dalInterfaceProperty.PrimaryTypeId);
        }

        /// <summary>
        /// Converti un objet NodeTypeProperty en PropertyX du DAL SubSonic
        /// </summary>
        /// <param name="pProperty">L'objet NodeTypeProperty à convertir</param>
        /// <returns>Un objet de type PropertyX</returns>
        private static DALS.PropertyX ToDALProperty(NodeTypeProperty pProperty)
        {
            DALS.PropertyX result = pProperty.IsNew
            ? new DALS.PropertyX() { PropertyId = pProperty.ID }
            : new DALS.PropertyX(pProperty.ID);

            //Important pour la synchronisation
            if (!pProperty.IsNew && result.PropertyId == Guid.Empty)
            {
                result.PropertyId = pProperty.ID;
            }

            result.Name = pProperty.Name;
            result.Description = pProperty.Description;
            result.TypeId = pProperty.TypeID;
            result.GroupName = pProperty.GroupName;
            result.MedianamikControlId = pProperty.MedianamikControlID;
            result.MedianamikControlHeight = pProperty.MedianamikControlInfo.Height;
            result.MedianamikControlWidth = pProperty.MedianamikControlInfo.Width == null ? null : pProperty.MedianamikControlInfo.Width.Value.ToString();
            result.TreeRootNodeId = pProperty.MedianamikControlInfo.TreeRootNodeID;
            result.Flags = pProperty.Flags.Data;
            result.HaveTooltip = pProperty.HaveTooltip;
            result.IsLanguageNeutral = pProperty.IsLanguageNeutral;
            result.IsUnique = pProperty.IsUnique;
            result.DataTypeId = pProperty.DataType.ID;
            if (pProperty.PrimaryDataType != null) { result.PrimaryDataTypeId = pProperty.PrimaryDataType.ID; }
            result.MinLength = pProperty.MinLength;
            result.MaxLength = pProperty.MaxLength;
            result.ValidationRegex = pProperty.ValidationRegex == null
                                          ? null
                                          : pProperty.ValidationRegex.ToString();
            result.IsRequired = pProperty.IsRequired;
            result.PrimaryPropertyId = pProperty.PrimaryPropertyID;
            result.PrimaryTypeId = pProperty.PrimaryTypeID;
            result.PrimaryMedianamikControlId = pProperty.PrimaryMedianamikControlID;
            result.PrimaryMedianamikControlWidth = pProperty.PrimaryMedianamikControlInfo.Width == null ? null : pProperty.PrimaryMedianamikControlInfo.Width.Value.ToString();
            result.PrimaryMedianamikControlHeight = pProperty.PrimaryMedianamikControlInfo.Height;
            result.PrimaryTreeRootNodeId = pProperty.PrimaryMedianamikControlInfo.TreeRootNodeID;

            result.Roles = pProperty.Roles.ToString();

            result.IsGenerated = pProperty.IsGenerated;
            result.IsDeleted = pProperty.IsDeleted;
            result.RelationshipId = (int) pProperty.Relationship;

            return result;
        }

        private static DALS.TypeInterface ToDALTypeInterface(NodeTypeInterfaceImplementation pInterface)
        {
            var result = pInterface.Status == EntityStates.New
            ? new DALS.TypeInterface() { Id  = pInterface.ID }
            : new DALS.TypeInterface(pInterface.ID);

            result.InterfaceId = pInterface.InterfaceId;
            result.TypeId = pInterface.OwnerId;

            return result;
        }

        private static DALS.InterfaceProperty ToDALInterfaceProperty(NodeTypeInterfaceProperty property)
        {
            var result = property.Status == EntityStates.New
           ? new DALS.InterfaceProperty() { InterfacePropertyId = property.ID }
           : new DALS.InterfaceProperty(property.ID);

            //Important pour la synchronisation
            if (property.Status != EntityStates.New && result.InterfacePropertyId == Guid.Empty)
            {
                result.InterfacePropertyId = property.ID;
            }

            result.Name = property.Name;
            result.Description = property.Description;
            result.DataTypeId = property.DataTypeId;
            result.InterfaceId = property.OwnerId;
            result.MaxLength = property.MaxLength;
            result.PrimaryTypeId = property.PrimaryTypeID;

            return result;
        }
        
        private static NodeTypeInterface FromDALInterface(DALS.InterfaceX dalInterface)
        {
            return new NodeTypeInterface(dalInterface.InterfaceId, dalInterface.Name, dalInterface.Description);
        }

        private static NodeTypeInterfaceImplementation FromDALTypeInterface(DALS.TypeInterface dalInterface)
        {
            return new NodeTypeInterfaceImplementation(dalInterface.Id, dalInterface.TypeId, dalInterface.InterfaceId);
        }

        /// <summary>
        /// Converti un objet de type NodeType en Type du DAL SubSonic
        /// </summary>
        /// <param name="pType">L'objet de type NodeType à convertir</param>
        /// <param name="pDALProperties">Paramètre de sortie.
        /// Permet de récupérer la collection de PropertyX du Type Medianamik</param>
        /// <returns>Un objet de type Type du DAL SubSonic</returns>
        private static DALS.Type ToDALType(NodeType pType, out DALS.PropertyXCollection pDALProperties)
        {
            DALS.Type result = pType.Status == EntityStates.New
            ? new DALS.Type() { TypeId = pType.ID }
            : new DALS.Type(pType.ID);

            result.ParentTypeId = pType.ParentID;
            result.CanHaveChilds = pType.IsInheritable;
            result.Name = pType.Name;
            result.Description = pType.Description;
            result.IsManyToMany = pType.IsManyToMany;
            result.IsGenerated = pType.IsGenerated;
            result.IsAdmin = pType.IsAdmin;
            result.Flags = pType.Flags.Data;
            result.IsSystem = pType.IsSystem;
            result.IsAbstract = pType.IsAbstract;
            result.IsDeleted = pType.IsDeleted;
            result.ExtendedProperties = pType.ExtendedProperties.Document.ToString();

            pDALProperties = new DALS.PropertyXCollection();
            pDALProperties.AddRange(pType.Properties.Select(p => ToDALProperty(p)));

            return result;

        }

        private static DALS.Type ToDALType(NodeType pType)
        {
            DALS.Type result = pType.Status == EntityStates.New
            ? new DALS.Type() { TypeId = pType.ID }
            : new DALS.Type(pType.ID);

            result.ParentTypeId = pType.ParentID;
            result.CanHaveChilds = pType.IsInheritable;
            result.Name = pType.Name;
            result.Description = pType.Description;
            result.IsManyToMany = pType.IsManyToMany;
            result.IsGenerated = pType.IsGenerated;
            result.IsAdmin = pType.IsAdmin;
            result.Flags = pType.Flags.Data;
            result.IsSystem = pType.IsSystem;
            result.IsAbstract = pType.IsAbstract;
            result.IsVersioned = pType.IsVersioned;
            result.IsDeleted = pType.IsDeleted;
            result.ExtendedProperties = pType.ExtendedProperties.Document.ToString();

            return result;
        }

        private static DALS.InterfaceX ToDALInterface(NodeTypeInterface pInterface)
        {
            var result = pInterface.Status == EntityStates.New
           ? new DALS.InterfaceX() { InterfaceId = pInterface.ID }
           : new DALS.InterfaceX(pInterface.ID);

            result.Name = pInterface.Name;
            result.Description = pInterface.Description;

            return result;
        }

        private static OneToManyRelation FromDALOneToManyRelation(DALS.OneToManyRelation pDALOneToManyRelation)
        {
            OneToManyRelation relation = new OneToManyRelation(pDALOneToManyRelation.PrimaryPropertyId
                , pDALOneToManyRelation.PrimaryTypeId
                , pDALOneToManyRelation.ForeignPropertyid
                , pDALOneToManyRelation.ForeignTypeId
                
                , pDALOneToManyRelation.PrimaryPropertyName
                , pDALOneToManyRelation.PrimaryTypeName
                , pDALOneToManyRelation.ForeignPropertyName
                , pDALOneToManyRelation.ForeignTypeName
                , pDALOneToManyRelation.ForeignTypeIsManyToMany                
                , false);

            return relation;
        }

        private static ManyToManyRelation FromDALManyToManyRelation(DALS.ManyToManyRelation pDALManyToManyRelation)
        {
            OneToManyRelation leftRelation = new OneToManyRelation(pDALManyToManyRelation.LeftPrimaryPropertyId
                , pDALManyToManyRelation.LeftPrimaryTypeId
                , pDALManyToManyRelation.LeftForeignPropertyId
                , pDALManyToManyRelation.ForeignTypeId

                , pDALManyToManyRelation.LeftPrimaryPropertyName
                , pDALManyToManyRelation.LeftPrimaryTypeName
                , pDALManyToManyRelation.LeftForeignPropertyName                
                , pDALManyToManyRelation.ForeignTypeName                
                , pDALManyToManyRelation.ForeignTypeIsManyToMany
                , false);

            OneToManyRelation rightRelation = new OneToManyRelation(pDALManyToManyRelation.RightPrimaryPropertyId
                , pDALManyToManyRelation.RightPrimaryTypeId
                , pDALManyToManyRelation.RightForeignPropertyId
                , pDALManyToManyRelation.ForeignTypeId

                , pDALManyToManyRelation.RightPrimaryPropertyName
                , pDALManyToManyRelation.RightPrimaryTypeName
                , pDALManyToManyRelation.RightForeignPropertyName
                , pDALManyToManyRelation.ForeignTypeName                
                , pDALManyToManyRelation.ForeignTypeIsManyToMany
                , false);

            ManyToManyRelation result = new ManyToManyRelation(leftRelation, rightRelation);
            return result;
        }

        private static DALS.HierarchicalRule ToDALHierarchicalRule(Guid pParentTypeId, Guid pTypeId)
        {
            DALS.HierarchicalRule result = new DALS.HierarchicalRule();
            result.IsNew = true;
            result.IsLoaded = false;
            result.ParentItemId = pParentTypeId;
            result.TypeId = pTypeId;
            result.ParentItemType = false;

            return result;
        }

        private static DALS.HierarchicalRule ToDALHierarchicalNodeRule(Guid pParentNodeId, Guid pTypeId)
        {
            DALS.HierarchicalRule result = new DALS.HierarchicalRule();
            result.IsNew = true;
            result.IsLoaded = false;
            result.ParentItemId = pParentNodeId;
            result.TypeId = pTypeId;
            result.ParentItemType = true;

            return result;
        }

        private static NodeType NodeTypeFromDALHierarchicalRule(Guid? pId, string pName,
            bool pCanHaveChilds, bool pIsGenerated, bool pIsAbstract, bool pIsSystem, string pPath, int pDepth)
        {
            if (pId.HasValue)
            {
                return new NodeType(pId.Value, pName, pCanHaveChilds, pIsGenerated, pIsAbstract, pIsSystem, false, pPath, pDepth);
            }
            else
            {
                //Type fake représentant la racine
                //TODO : Gestion des mots réservés (Exemple : ROOT)
                return new NodeType(Guid.Empty, "Root", true, false, true, true, false, string.Empty, 0);
            }
        }

        private static DALS.TypeTemplate ToDALTypeTemplate(TypeTemplate template)
        {
            DALS.TypeTemplate result = new DALS.TypeTemplate();
            result.IsNew = true;
            result.IsLoaded = false;
            result.WebSiteId = template.WebSiteId;
            result.TypeId = template.NodeTypeId.GetValueOrDefault();
            result.TemplateId = template.TemplateId;

            return result;
        }

        #endregion
    }
}
